/**********************************************************************
* Filename: Grupo.java
* Created: 2012/04/30
* @author Fernando Brito e Abreu
**********************************************************************/
package pt.iscteiul.worldfootball.businesslayer;

import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

import com.projectpoint.annotationnotfinished.NotFinished;

@NotFinished(value="Not tested")
public class Grupo implements Cloneable
{
	public static Set<Grupo> allInstances = new HashSet<Grupo>();
	
	private String designacao;
	private FaseCampeonato fase;
	private Campeonato campeonato;
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Grupo grupo = new Grupo(new String(designacao), fase, (Campeonato)campeonato.clone());
		Grupo.allInstances.remove(grupo);
		return grupo;
	}
	
	protected boolean _Invariant(){
		//let c = self.campeonato in self.paises.forAll(p|p.participado.exists(c1|c1=c))
		boolean membrosDoGrupoTemDePertencerAoCampeonato = true;
		{
			Campeonato c = this.campeonato();
			for(Pais p:this.paises()){
				boolean exists = false;
				for(Campeonato campeonato:p.participado()){
					if(campeonato==c){
						exists=true;
						break;
					}
				}
				if(!exists){
					membrosDoGrupoTemDePertencerAoCampeonato = false;
					break;
				}
			}
		}
		return membrosDoGrupoTemDePertencerAoCampeonato;
	} 
	
	
	/**********************************************************************
	* Default constructor
	**********************************************************************/
	public Grupo()
	{
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Parameterized constructor
	* @param designacao the designacao to initialize
	* @param fase the fase to initialize
	* @param campeonato the campeonato to initialize
	**********************************************************************/
	public Grupo(String designacao, FaseCampeonato fase, Campeonato campeonato)
	{
		this.designacao = designacao;
		this.fase = fase;
		this.campeonato = campeonato;
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the designacao of the grupo
	**********************************************************************/
	public String designacao()
	{
		return designacao;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param designacao the designacao to set
	**********************************************************************/
	public void setDesignacao(String designacao)
	{
		this.designacao = designacao;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the fase of the grupo
	**********************************************************************/
	public FaseCampeonato fase()
	{
		return fase;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param fase the fase to set
	**********************************************************************/
	public void setFase(FaseCampeonato fase)
	{
		this.fase = fase;
	}
	
	/**********************************************************************
	* ONE2MANY getter for Grupo[*] <-> Campeonato[1]
	* @return the campeonato of the grupo
	**********************************************************************/
	public Campeonato campeonato()
	{
		return campeonato;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Grupo[*] <-> Campeonato[1]
	* @param campeonato the campeonato to set
	**********************************************************************/
	public void setCampeonato(Campeonato campeonato)
	{
		this.campeonato = campeonato;
	}
	
	/**********************************************************************
	* ONE2MANY getter for Grupo[1] <-> Jogo[*]
	* @return the jogos of the grupo
	**********************************************************************/
	public Set<Jogo> jogos()
	{
		Set<Jogo> result = new HashSet<Jogo>();
		for (Jogo x : Jogo.allInstances)
			if (x.grupo()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Grupo[1] <-> Jogo[*]
	* @param jogos the jogos to set
	**********************************************************************/
	public void setJogos(Set<Jogo> jogos)
	{
		for (Jogo x : jogos)
			x.setGrupo(this);
	}
	
	/**********************************************************************
	* ONE2MANY getter for Grupo[0..1] <-> Pais[*]
	* @return the paises of the grupo
	**********************************************************************/
	public Set<Pais> paises()
	{
		Set<Pais> result = new HashSet<Pais>();
		for (Pais x : Pais.allInstances)
			if (x.grupo()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Grupo[0..1] <-> Pais[*]
	* @param paises the paises to set
	**********************************************************************/
	public void setPaises(Set<Pais> paises)
	{
		for (Pais x : paises)
			x.setGrupo(this);
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param designacao the designacao to set
	* @param fase the fase to set
	* @param paises the paises to set
	**********************************************************************/
	public void inicializa(String designacao, FaseCampeonato fase, Set<Pais> paises)
	{
		//	TODO
		//	self.designacao := designacao;
		this.designacao = designacao;
		//	self.fase := fase;
		this.fase = fase;
		//	for p in paises do insert (self,p) into Grupo_Pais end;
		for(Pais p: paises){
			p.setGrupo(this);
		}
		
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param p the p to set
	**********************************************************************/
	public HashMap<Pais,Set<Jogo>> obterJogosDoGrupo(Set<Pais> p)
	{	//	TODO
		//	return p->collect(each : Pais | Tuple {pais:each,jogos:self.jogos})->asSet
		HashMap<Pais,Set<Jogo>> returned = new HashMap<Pais,Set<Jogo>>();
		for(Pais pais: p){
			returned.put(pais, pais.jogo());
		}
		return returned;
	}
	
	/* (non-Javadoc)
	* @see java.lang.Object#toString()
	*/
	@Override
	/**********************************************************************
	* Object serializer
	**********************************************************************/
	public String toString()
	{
		return "Grupo [designacao=" + designacao + ", fase=" + fase + ", campeonato=" + campeonato + "]\n";
	}
	
}
